#include "comment.header"

/* Generated by Interface Builder */

#import <appkit/appkit.h>
#import <appkit/PrintInfo.h>

#include <string.h>
#import "GoApp.h"
#import "Board.h"
#import "ClickCell.h"
#include "igs.h"
#include "godict.h"

#define CURRENT_VERSION	"Version 2.3"

unsigned char p[19][19], l[19][19], ma[19][19], ml[19][19];
char special_characters[19][19], sgComment[2000], sgNodeName[200];
int hist[19][19], currentMoveNumber;
int rd, lib, play, pass, handicap, whiteSide, blackSide, MAXX, MAXY;
int currentStone, opposingStone, blackCaptured, whiteCaptured;
int blackTerritory, whiteTerritory, SmartGoGameFlag, initialization;
float black_Score, white_Score;
int blackCapturedKoI, blackCapturedKoJ, whiteCapturedKoI, whiteCapturedKoJ;
int bothSides, neitherSide, blackPassed, whitePassed, manualScoring, manScoreTemp;
int typeOfScoring, AGAScoring;
int opn[9];                               // opening pattern flag
int gameType;
BOOL finished, printBold;
gameHistory gameMoves[500];
int lastMove;
node *SGgameMoves, *currentNode, *rootNode;
FILE *smartGoInputFile;
char *SGfile, *currentSGfilePosition;
char *IGSStatusText, IGSPasswordText[20], IGSLoginText[20];
GODICT *godict;

void getAppDirectory(char *appDirectory)
{
  FILE *process;
  char command[256];
  char *suffix;

  strcpy(appDirectory, NXArgv[0]);
  if (appDirectory[0] == '/')
    {
      if (suffix = rindex(appDirectory,'/'))
	*suffix = '\0';
    }
  else
    {
      sprintf(command, "which '%s'\n", NXArgv[0]);
      process = popen(command,"r");
      fscanf(process, "%s", appDirectory);
      pclose(process);
      if (suffix = rindex(appDirectory, '/'))
	*suffix = '\0';
      chdir(appDirectory);
      getwd(appDirectory);
    }
}

char *getpassword(void)
{
  return IGSPasswordText;
}

char *getloginname(void)
{
  return IGSLoginText;
}

void checkingNetTraffic(DPSTimedEntry timedEntry, double timeNow, void *data)
{
  [(id)data checkNetTraffic];
}

void IGSSendString(char *s)
{
  sendstr(s);

  printBold = YES;
  [NXApp SetIGSStatus:s];
}

void stripBrackets(char s[])
{
  int i, j;

  i = 0;
  while (i < strlen(s))
    {
      if ((s[i] == '[') || (s[i] == ']'))
	{
	  for (j = i; j < strlen(s) - 1; j++)
	    s[j] = s[j+1];
	  s[strlen(s) - 1] = 0;
	}
      else
	{
	  i++;
	}
    }
}

int saveNeXTGoFile(const char *fileName)
{
  FILE *NGoFile;
  int i, j;

  if ((NGoFile = fopen(fileName, "w")) == NULL)
    return 1;

  fprintf(NGoFile, "%d\n", handicap);
  fprintf(NGoFile, "%d\n", whiteSide);
  fprintf(NGoFile, "%d\n", blackSide);
  fprintf(NGoFile, "%d\n", MAXX);
  fprintf(NGoFile, "%d\n", MAXY);
  fprintf(NGoFile, "%d\n", currentStone);
  fprintf(NGoFile, "%d\n", opposingStone);
  fprintf(NGoFile, "%d\n", blackCaptured);
  fprintf(NGoFile, "%d\n", whiteCaptured);
  fprintf(NGoFile, "%d\n", blackCapturedKoI);
  fprintf(NGoFile, "%d\n", blackCapturedKoJ);
  fprintf(NGoFile, "%d\n", whiteCapturedKoI);
  fprintf(NGoFile, "%d\n", whiteCapturedKoJ);
  fprintf(NGoFile, "%d\n", bothSides);
  fprintf(NGoFile, "%d\n", neitherSide);
  fprintf(NGoFile, "%d\n", blackPassed);
  fprintf(NGoFile, "%d\n", whitePassed);
  for (i = 0; i < 9; i++)
    fprintf(NGoFile, "%d\n", opn[i]);
  for (i = 0; i < MAXX; i++)
    for (j = 0; j < MAXY; j++)
      fprintf(NGoFile, "%d\n", p[i][j]);
      
  fclose(NGoFile);

  return 0;
}

int saveSmartGoFile(const char *fileName)
{
  FILE *NGoFile;
  int i;

  if ((NGoFile = fopen(fileName, "w")) == NULL)
    return 1;
  fprintf(NGoFile, "(\n;\nGaMe[1]\nVieW[]\n");
  fprintf(NGoFile, "SiZe[%d]\nKoMi[%3.1f]\nHAndicap[%d]", MAXX, 
	  ((handicap == 0)?KOMI:0.5), handicap);
  fprintf(NGoFile,"\nComment[ A game between ");

  if (gameType != LOCAL)
    {
      fprintf(NGoFile, "two people on the network.\n\n");
    }
  else if (neitherSide)
    {
      fprintf(NGoFile,"two human players.\n\n");
    }
  else if (bothSides)
    {
      fprintf(NGoFile,"two computer players.\n\n");
    }
  else
    {
      fprintf(NGoFile,"the computer and a human player.\n\n");
    }

  if (finished)
    {
      fprintf(NGoFile,"        Result:  %s wins by %8.1f.]\n",
	      (black_Score > white_Score)?"Black":"White",
	      fabs(black_Score - white_Score));
    }
  else
    {
      fprintf(NGoFile, "]\n");
    }

  if (handicap > 1)
    {
      int q, half;

      q = (MAXX < 13)?2:3;
      half = (MAXX + 1)/2 - 1;

      switch (handicap) {
      case 2:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c]\n", q+'a', MAXY-q-1+'a',
		MAXX-q-1+'a', q+'a');
	break;
      case 3:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c]\n", q+'a', MAXY-q-1+'a',
		MAXX-q-1+'a', q+'a', q+'a', q+'a');
	break;
      case 4:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c]\n", q+'a',
		MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a', MAXX-q-1+'a',
		MAXY-q-1+'a');
	break;
      case 5:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c]\n", q+'a',
		MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a', MAXX-q-1+'a',
		MAXY-q-1+'a', half+'a', half+'a');
	break;
      case 6:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a');
	break;
      case 7:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a', half+'a', half+'a');
	break;
      case 8:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a', half+'a', q+'a', half+'a', MAXY-q-1+'a');
	break;
      case 9:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a', half+'a', q+'a', half+'a', MAXY-q-1+'a', half+'a',
		half+'a');
	break;
      }
    }
    
  for (i = 0; i < lastMove; i++)
    {
      switch (gameMoves[i].color)
	{
	case 1:
	  if (gameMoves[i].x >= 0)
	    {
	      fprintf(NGoFile,";\nWhite[%c%c]\n", gameMoves[i].x+97,
		      gameMoves[i].y+97);
	    }
	  else
	    {
	      fprintf(NGoFile, ";\nWhite[tt]\n");
	    }
	  break;
	case 2:
	  if (gameMoves[i].x >= 0)
	    {
	      fprintf(NGoFile,";\nBlack[%c%c]\n", gameMoves[i].x+97,
		      gameMoves[i].y+97);
	    }
	  else
	    {
	      fprintf(NGoFile, ";\nBlack[tt]\n");
	    }
	  break;
	}
    }

  fprintf(NGoFile,")\n\n");
  fclose(NGoFile);

  return 0;
}

@implementation GoApp

- appDidInit:app 
{
  FILE *NeXTGoPrefs;
  char str[80];
  
  godict = NULL;
  IGSfont = [Font newFont:"Ohlfs" size:10];
  IGSboldFont = [Font newFont:"Helvetica" size:10];
  [[MainGoView window] setMiniwindowIcon:"NeXTGoFile"];
  strcpy(str, "NeXTGo -- ");
  strcat(str, CURRENT_VERSION);
  [versionString setStringValue:CURRENT_VERSION];
  [[MainGoView window] setTitle:str];
  [[IGSStatus docView] setFont:IGSfont];
  [[smartGoComments docView] setFont:IGSfont];
  
  lastMove = 0;
  gameType = LOCAL;

  strcpy(str, NXHomeDirectory());
  strcat(str, "/.NeXTGoPrefs");

  if ((NeXTGoPrefs = fopen(str, "r")) != NULL)
    {
      fscanf(NeXTGoPrefs, "%d", &handicap);
      fscanf(NeXTGoPrefs, "%d", &MAXX);
      fscanf(NeXTGoPrefs, "%d", &blackSide);
      fscanf(NeXTGoPrefs, "%d", &whiteSide);
      fscanf(NeXTGoPrefs, "%d", &manualScoring);
      fscanf(NeXTGoPrefs, "%d", &typeOfScoring);
      fscanf(NeXTGoPrefs, "%d", &AGAScoring);
      fscanf(NeXTGoPrefs, "%s", servename);
      fscanf(NeXTGoPrefs, "%s", IGSPasswordText);
      fscanf(NeXTGoPrefs, "%s", IGSLoginText);
      fclose(NeXTGoPrefs);
      
      MAXY = MAXX;
      manScoreTemp = manualScoring;

      [handicapSlider setIntValue:handicap];
      [handicapText setIntValue:handicap];
      [sizeSlider setIntValue:MAXX];
      [sizeText setIntValue:MAXX];
      [BlackPlayer selectCellAt:blackSide:0];
      [WhitePlayer selectCellAt:whiteSide:0];
      [scoringMethod selectCellAt:manualScoring:0];
      [scoringType selectCellAt:typeOfScoring:0];
      [AGAscoringMethodFlag setIntValue:AGAScoring];
      [savePrefsFlag setIntValue:1];
      [IGSAddress setStringValue:servename];
      [IGSLoginName setStringValue:IGSLoginText];
      [IGSPassword setStringValue:IGSPasswordText];
    }
    
  neitherSide = 0;
  bothSides = 0;
  manScoreTemp = manualScoring;
    
  if ((blackSide == 0) && (whiteSide == 0))
    neitherSide++;
  if ((blackSide == 1) && (whiteSide == 1))
    bothSides++;
	
  [self NewGame:self];

  [[[NXApp printInfo] setHorizCentered:YES] setVertCentered:YES];

  openReq = [OpenPanel new];
  saveReq = [SavePanel new];

  SmartGoGameFlag = 0;
  
  return self;
}

- showError: (const char *)errorMessage
{
  NXRunAlertPanel("NeXTGo Error", errorMessage,"OK", NULL, NULL);
  return self;
}

- UserPass:sender
{
  if (SmartGoGameFlag)
    return self;

  [MainGoView passMove];

  return self;
}

- stopGame:sender
{
  if (SmartGoGameFlag)
    return self;

  [MainGoView stop:self];
    
  return self;
}

- startGame:sender
{
  if (SmartGoGameFlag)
    return self;

  [MainGoView go:self];

  return self;
}

- NewGame:sender
{
  int resp;

  if (gameType == IGSGAME)
    {
      NXRunAlertPanel("IGS Error", "You must first close your IGS session before\n\
beginning a new game.", "OK", NULL, NULL);
      return self;
    }

  if (SmartGoGameFlag)
    {
      SmartGoGameFlag = 0;
      [smartGoPanel close];
    }
    
  gameType = LOCAL;

  if ((lastMove > 0) && (!finished))
    {
      resp = NXRunAlertPanel("NeXTGo Warning", "A game is in process.  Do you wish to abandon it?", "Abandon", "Cancel", 0);

      if (resp == NX_ALERTALTERNATE)
	return self;
    }

  [MainGoView startNewGame];
  [MainGoView display];

  lastMove = 0;

  return self;
}

- SetPreferences:sender
{
  FILE *NeXTGoPrefs;
  char str[80];

  handicap = [handicapSlider intValue];
  MAXX = MAXY = [sizeSlider intValue];
  blackSide = [BlackPlayer selectedRow];
  whiteSide = [WhitePlayer selectedRow];
  manualScoring = [scoringMethod selectedRow];
  typeOfScoring = [scoringType selectedRow];
  AGAScoring = [AGAscoringMethodFlag intValue];
  strcpy(servename, (char *)[IGSAddress stringValue]);
  strcpy(IGSPasswordText, (char *)[IGSPassword stringValue]);
  strcpy(IGSLoginText, (char *)[IGSLoginName stringValue]);
    
  neitherSide = 0;
  bothSides = 0;
  manScoreTemp = manualScoring;
    
  if ((blackSide == 0) && (whiteSide == 0))
    neitherSide++;
  if ((blackSide == 1) && (whiteSide == 1))
    bothSides++;
	
  [self NewGame:self];
    
  [prefPanel close];
  
  if ([savePrefsFlag intValue])
  {
    strcpy(str, NXHomeDirectory());
    strcat(str, "/.NeXTGoPrefs");
    if ((NeXTGoPrefs = fopen(str, "w")) == NULL)
      {
        NXRunAlertPanel("NeXTGo Error", "I cannot write to the preferences file.",
			"OK", 0, 0);
        [self NewGame:self];
        return self;
      }
    fprintf(NeXTGoPrefs, "%d  ", handicap);
    fprintf(NeXTGoPrefs, "%d  ", MAXX);
    fprintf(NeXTGoPrefs, "%d  ", blackSide);
    fprintf(NeXTGoPrefs, "%d  ", whiteSide);
    fprintf(NeXTGoPrefs, "%d  ", manualScoring);
    fprintf(NeXTGoPrefs, "%d  ", typeOfScoring);
    fprintf(NeXTGoPrefs, "%d  ", AGAScoring);
    fprintf(NeXTGoPrefs, "%s  ", servename);
    fprintf(NeXTGoPrefs, "%s  ", IGSPasswordText);
    fprintf(NeXTGoPrefs, "%s\n\n", IGSLoginText);
    fclose(NeXTGoPrefs);
  }

  return self;
}

- displayNewSGNode
{
  node *var_list, *current_var;

  [smartGoNodeNumber setIntValue:currentNode->nodenum];
  [[smartGoComments docView] setText:""];
  [[smartgoVariants docView] setText:""];
  [self AddSGComment:sgComment];
  [self SetSGNodeName:sgNodeName];

  [MainGoView display];
  [MainGoView setblacksPrisoners:blackCaptured];
  [MainGoView setwhitesPrisoners:whiteCaptured];

  for (var_list = currentNode->variants; var_list != NULL;
       var_list = var_list->next_var)
    {
      char var_name[80];

      current_var = var_list;
      while (current_var->properties == NULL)
	{
	  current_var = forwardOneNode(current_var);
	}

      sgNodeName[0] = 0;
      buildToNode(current_var);
      sprintf(var_name, "%d: %s", current_var->nodenum, sgNodeName);
      [self AddSGVariantName:var_name];
    }

  if (currentNode->variants != NULL)
    {
      sgNodeName[0] = 0;
      sgComment[0] = 0;
      buildToNode(currentNode);
    }

  return self;
}

- stepSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = stepForward(currentNode);

  [self displayNewSGNode];

  return self;
}

- stepBackSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = stepBackward(currentNode);

  [self displayNewSGNode];

  return self;
}

- jumpSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = jumpForward(currentNode);

  [self displayNewSGNode];

  return self;
}

- jumpBackSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = jumpBackward(currentNode);

  [self displayNewSGNode];

  return self;
}

- AddSGComment:(char *)s
{
  Text *docView = [smartGoComments docView];
  int dvLen;
  char retstr[5];

  strcpy(retstr, "\n");

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView replaceSel: s];

  [docView setSel:[docView textLength] :[docView textLength]];

  [docView scrollSelToVisible];

  return self;
}

- AddSGVariantName:(char *)s
{
  Text *docView = [smartgoVariants docView];
  int dvLen;
  char retstr[5];

  strcpy(retstr, "\n");

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView replaceSel: s];

  [docView setSel:[docView textLength] :[docView textLength]];

  [docView replaceSel: retstr];
  [docView setSel:[docView textLength] :[docView textLength]];

  [docView scrollSelToVisible];

  return self;
}

- SetSGNodeName:(char *)s
{
  [smartGoNodeName setStringValue:s];
  [smartGoNodeName display];

  return self;
}

- openNeXTGoFileRequest:sender
{
  FILE *NGoFile;
  int i, j, t;
  const char *fileName;
  const char *const types[2] = {"nextgo", NULL};

  if ([openReq runModalForTypes:types] && (fileName = [openReq filename])) {

    if ((NGoFile = fopen(fileName, "r")) == NULL)
      return self;

    fscanf(NGoFile, "%d", &handicap);
    fscanf(NGoFile, "%d", &whiteSide);
    fscanf(NGoFile, "%d", &blackSide);
    fscanf(NGoFile, "%d", &MAXX);
    fscanf(NGoFile, "%d", &MAXY);
    [MainGoView startNewGame];
    fscanf(NGoFile, "%d", &opposingStone);
    fscanf(NGoFile, "%d", &currentStone);
    fscanf(NGoFile, "%d", &blackCaptured);
    fscanf(NGoFile, "%d", &whiteCaptured);
    fscanf(NGoFile, "%d", &blackCapturedKoI);
    fscanf(NGoFile, "%d", &blackCapturedKoJ);
    fscanf(NGoFile, "%d", &whiteCapturedKoI);
    fscanf(NGoFile, "%d", &whiteCapturedKoJ);
    fscanf(NGoFile, "%d", &bothSides);
    fscanf(NGoFile, "%d", &neitherSide);
    fscanf(NGoFile, "%d", &blackPassed);
    fscanf(NGoFile, "%d", &whitePassed);
    for (i = 0; i < 9; i++)
      {
        fscanf(NGoFile, "%d", &t);
	opn[i] = t;
      }
    for (i = 0; i < MAXX; i++)
      for (j = 0; j < MAXY; j++)
        {
          fscanf(NGoFile, "%d", &t);
	  p[i][j] = t;
	}
    [MainGoView updateInfo];

    fclose(NGoFile);
    
    [MainGoView lockFocus];
    [[MainGoView window] flushWindow];
    [MainGoView display];
    [MainGoView unlockFocus];    
  } else [self showError:"Error on Open Request"];

  NXPing();

  return self;
}

- initTranslator:sender
{
  char filename[256];

  getAppDirectory(filename);
  strcat(filename,"/");
  strcat(filename,DEFDICT);

  if (godict == NULL)
    {
      godict = load_dict(filename);

      if (godict == NULL)
	{
	  NXRunAlertPanel("Translate Error","There is a problem opening the dictionary file.", "OK", 0, 0);
	  return self;
	}
    }

  [translateWindow makeKeyAndOrderFront:self];
  [translateWindow setMiniwindowIcon:"NeXTGoFile"];
  [translateWindow display];
  [translateTerm setStringValue:""];
  [translateTerm selectText:self];
  [translateButton setEnabled:YES];
  [[translateResults docView] setText:""];

  return self;
}

- performTranslate:sender
{
  GODICT *d;
  char term[80];
  extern int termtypes, languages;

  strcpy(term, [translateTerm stringValue]);
  if (strlen(term) == 0)
    return self;

  termtypes = CD_MISC*[transTypeMISC intValue];
  termtypes += CD_NAME*[transTypeNAME intValue];
  termtypes += CD_CHAM*[transTypeCHAM intValue];
  termtypes += CD_TECH*[transTypeTECH intValue];
  termtypes += CD_POLI*[transTypePOLI intValue];
  termtypes += CD_DIGI*[transTypeDIGI intValue];

  languages = LANG_DG*[transLangDG intValue];
  languages += LANG_CP*[transLangCP intValue];
  languages += LANG_JP*[transLangJP intValue];
  languages += LANG_CH*[transLangCH intValue];
  languages += LANG_RK*[transLangRK intValue];
  languages += LANG_GB*[transLangGB intValue];
  languages += LANG_NL*[transLangNL intValue];
  languages += LANG_GE*[transLangGE intValue];
  languages += LANG_FR*[transLangFR intValue];

  [[translateResults docView] setText:""];
  d = godict;

  while (d != NULL)
    {
      d = search_dict(d,term);
      if (d != NULL)
	{
	  [self translateOutput:d];
	  d = d->dct_next;
	}
    }
  [translateTerm selectText:self];

  return self;
}

- translateOutput:(GODICT *)d
{
  extern int languages;

  printBold = YES;
  [self addTranslateResults:LB_CD];
  switch(d->dct_type)
    {
    case CD_CHAM:
      [self addTranslateResults:MSG_CHAM];
      break;
    case CD_TECH:
      [self addTranslateResults:MSG_TECH];
      break;
    case CD_NAME:
      [self addTranslateResults:MSG_NAME];
      break;
    case CD_POLI:
      [self addTranslateResults:MSG_POLI];
      break;
    case CD_DIGI:
      [self addTranslateResults:MSG_DIGI];
      break;
    default:
      [self addTranslateResults:MSG_MISC];
      break;
    }

  [self addTranslateResults:"\n"];

  if (d->dct_jp && (languages & (LANG_JP)))
    {
      printBold = YES;
      [self addTranslateResults:LB_JP];
      [self addTranslateResults:d->dct_jp];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_ch && (languages & (LANG_CH)))
    {
      printBold = YES;
      [self addTranslateResults:LB_CH];
      [self addTranslateResults:d->dct_ch];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_rk && (languages & (LANG_RK)))
    {
      printBold = YES;
      [self addTranslateResults:LB_RK];
      [self addTranslateResults:d->dct_rk];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_gb && (languages & (LANG_GB)))
    {
      printBold = YES;
      [self addTranslateResults:LB_GB];
      [self addTranslateResults:d->dct_gb];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_nl && (languages & (LANG_NL)))
    {
      printBold = YES;
      [self addTranslateResults:LB_NL];
      [self addTranslateResults:d->dct_nl];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_ge && (languages & (LANG_GE)))
    {
      printBold = YES;
      [self addTranslateResults:LB_GE];
      [self addTranslateResults:d->dct_ge];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_fr && (languages & (LANG_FR)))
    {
      printBold = YES;
      [self addTranslateResults:LB_FR];
      [self addTranslateResults:d->dct_fr];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_dg && (languages & (LANG_DG)))
    {
      printBold = YES;
      [self addTranslateResults:LB_DG];
      [self addTranslateResults:"\n"];
      [self addTranslateResults:d->dct_dg];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_cp && (languages & (LANG_CP)))
    {
      printBold = YES;
      [self addTranslateResults:LB_CP];
      [self addTranslateResults:d->dct_cp];
      [self addTranslateResults:"\n"];
    }

  [self addTranslateResults:"\n\n"];

  return self;
}

- addTranslateResults:(char *)s
{
  Text *docView = [translateResults docView];
  int dvLen;

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView setSelFont:IGSfont];
  printBold = NO;
  [docView replaceSel:s];
  [docView setSel:[docView textLength] :[docView textLength]];

  [docView scrollSelToVisible];

  return self;
}

- saveNeXTGoFileRequest:sender
{
  const char *fileName;
  const char *const types[2] = {"nextgo", NULL};

  [saveReq setRequiredFileType:types[0]];

  if (([saveReq runModalForDirectory:""
      file:""]) && (fileName = [saveReq filename]))
    {
      saveNeXTGoFile(fileName);
    }
    
  NXPing();
  
  return self;
}

- openSmartGoFileRequest:sender
{
  const char *fileName;
  const char *const types[2] = {"", NULL};
  char dispFileName[80];
  int i, j;
  struct stat statbuf;

  if (gameType != LOCAL)
    {
      NXRunAlertPanel("IGS Error", "You must first close your IGS session before\n\
opening a Smart-Go file.", "OK", NULL, NULL);
      return self;
    }

  if ([openReq runModalForTypes:types] && (fileName = [openReq filename])) {

    if ((smartGoInputFile = fopen(fileName, "r")) == NULL)
      return self;

    SGgameMoves = NULL;
    SmartGoGameFlag = 1;
    initialization = 0;

    [smartGoPanel makeKeyAndOrderFront:self];
    [smartGoPanel setMiniwindowIcon:"NeXTGoFile"];
    [smartGoPanel display];
    [stepForwardButton setEnabled:YES];

    stat(fileName, &statbuf);
    SGfile = (char *) malloc ((size_t)statbuf.st_size+10);
    if (fread(SGfile, statbuf.st_size, 1, smartGoInputFile) != 1)
      {
	[self showError:"Error on Read"];
	fclose(smartGoInputFile);
	free(SGfile);

	return self;
      }

    fclose(smartGoInputFile);

    [MainGoView startNewGame];
    [MainGoView setMess1:"Smart-Go Playback"];
    j = 0;
    for (i = 0; i < strlen(fileName); i++)
      if (fileName[i] == '/')
	j = i;
    for (i = j+1; i < strlen(fileName); i++)
      dispFileName[i-j-1] = fileName[i];
    dispFileName[strlen(fileName) - j - 1] = 0;

    [MainGoView setMess2:dispFileName];

    rootNode = parse_tree(SGfile);
    MAXX = MAXY = 19;
    currentNode = stepForward(rootNode);
    [self displayNewSGNode];
  } else
    [self showError:"Error on Open Request"];

  NXPing();

  return self;
}

- saveSmartGoFileRequest:sender
{
  const char *fileName;
  const char *const types[2] = {"mgt", NULL};

  [saveReq setRequiredFileType:types[0]];

  if (([saveReq runModalForDirectory:""
      file:""]) && (fileName = [saveReq filename]))
    {
      saveSmartGoFile(fileName);
    }
    
  NXPing();
  
  return self;
}

- IGSSendCommand:sender
{
  if (strncasecmp((char *)[IGSCommand stringValue], "observe", 7) == 0)
    {
      NXRunAlertPanel("IGS Error", "You must select a game to observe by pressing the observe button.", "OK", 0, 0);
    }
  else
    {
      IGSSendString((char *)[IGSCommand stringValue]);
      IGSSendString("\n");
    }

  [IGSCommand setStringValue:""];
  [IGSCommand selectText:self];

  return self;
}

- IGSConnect:sender
{
  char s[80];

  if (strlen((char *)[IGSLoginName stringValue]) == 0)
    {
      NXRunAlertPanel("IGS Error", "You must first set your login name in the Preferences panel.",
		      "OK", 0, 0);
      [prefPanel makeKeyAndOrderFront:self];
      [IGSLoginName selectText:self];

      return self;
    }

  if (strlen((char *)[IGSPassword stringValue]) == 0)
    {
      NXRunAlertPanel("IGS Error", "You must first set your password in the Preferences panel.",
		      "OK", 0, 0);
      [prefPanel makeKeyAndOrderFront:self];
      [IGSPassword selectText:self];

      return self;
    }

  sethost((char *)[IGSAddress stringValue]);
  setport(6969);
  strcpy(IGSPasswordText, (char *)[IGSPassword stringValue]);
  strcpy(IGSLoginText, (char *)[IGSLoginName stringValue]);
  [prefPanel close];
  
  if (SmartGoGameFlag)
    {
      SmartGoGameFlag = 0;
      [smartGoPanel close];
    }
    
  [[IGSStatus docView] setText:""];
  [IGSStatusPanel makeKeyAndOrderFront:self];
  [IGSStatusPanel setMiniwindowIcon:"NeXTGoFile"];
  [IGSPanel makeKeyAndOrderFront:self];
  [IGSPanel setMiniwindowIcon:"NeXTGoFile"];
  [IGSCommand selectText:self];
  
  if (open_connection())
    {      
      [self SetIGSStatus:"Unable to make a connection.\n"];
      gameType = LOCAL;

      NXRunAlertPanel("IGS Error", "I was unable to make a connection.", "OK", 0, 0);
      [IGSPanel close];
      [IGSStatusPanel close];

      return self;
    }
  
  [self SetIGSStatus:"Connection established."];
  sprintf(s, "Logging in as %s\n", IGSLoginText);
  [self SetIGSStatus:s];
  
  timer = DPSAddTimedEntry(0.25, &checkingNetTraffic, self, NX_BASETHRESHOLD);
  
  gameType = IGSGAME;
  finished = YES;
  idle = 1;

  initparser();

  return self;
}

- checkNetTraffic
{
  fd_set readers;
  struct timeval to;
  int sel;
  
  to.tv_sec = 0;
  to.tv_usec = 0;
  
  FD_ZERO(&readers);
  FD_SET(sock, &readers);
  
  sel = select(sock + 1, &readers, NULL, NULL, &to);
  if (FD_ISSET(sock, &readers))
    incomingserver();
    
  return self;
}

- SetIGSStatus:(char *)s
{
  Text *docView = [IGSStatus docView];
  int dvLen;
  char retstr[5];

  strcpy(retstr, "\n");

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView setSelFont:IGSfont];
  [docView replaceSel: s];
  if (printBold)
    {
      [docView setSel:dvLen :[docView textLength]];
      [docView setSelFont:IGSboldFont];
      [docView setSelFontStyle:NX_BOLD];
      printBold = NO;
    }
  else
    [docView setSel:[docView textLength] :[docView textLength]];

  if (s[strlen(s) - 1] != '\n')
    {
      [docView setSel:[docView textLength] :0];
      [docView replaceSel: retstr];
      [docView scrollSelToVisible];
    }

  [docView scrollSelToVisible];

  return self;
}

- getGoView
{
  return MainGoView;
}

/*
  The following methods are the various commands for the Internet Go Server
  */

- IGSadjourn:sender
{
  IGSSendString("adjourn");
  IGSSendString("\n");

  return self;
}

- IGSbest:sender
{
  IGSSendString("best ");
  IGSSendString("\n");

  return self;
}

- IGSdecline:sender
{
  IGSSendString("decline");
  IGSSendString("\n");

  return self;
}

- IGSdecrease:sender
{
  IGSSendString("decrease");
  IGSSendString("\n");

  return self;
}

- IGSdone:sender
{
  IGSSendString("done");
  IGSSendString("\n");

  return self;
}

- IGSgames:sender
{
  IGSSendString("games ");
  IGSSendString("\n");

  return self;
}

- IGSincrease:sender
{
  IGSSendString("increase");
  IGSSendString("\n");

  return self;
}

- IGSobserve:sender
{
  message mess;
  NXRect frameRect = {15, 30, 497, 226}, scrollRect = {0, 0, 497, 226};
  NXSize cellSize = {470, 30};
  char str[80];
  int i;

  idle = 0;

  getgames(&mess);
  observeMatrix = [[Matrix alloc] initFrame:&frameRect mode:NX_RADIOMODE
		 cellClass:[ClickCell class] numRows:0 numCols:1];
  [observeMatrix setCellSize:&cellSize];

  for (i = 0; i < mess.gamecount; i++)
    {
      sprintf(str, "%3d -- %12s [%3s] vs. %12s [%3s] (%3d %d %d %3.1f)",
	      mess.gamelist[i].gnum, mess.gamelist[i].white,
	      mess.gamelist[i].wrank, mess.gamelist[i].black,
	      mess.gamelist[i].brank, mess.gamelist[i].mnum,
	      mess.gamelist[i].bsize, mess.gamelist[i].hcap,
	      mess.gamelist[i].komi);
      [observeMatrix addRow];
      observeCell = [observeMatrix cellAt:i :0];
      [observeCell setStringValue:str];
      [observeCell setAlignment:NX_LEFTALIGNED];
    }
  [observeMatrix sizeToCells];

  observeScrollView = [[ScrollView alloc] initFrame:&scrollRect];
  [observeScrollView setVertScrollerRequired:YES];
  [observeScrollView setBorderType:NX_BEZEL];
  [observeScrollView setBackgroundGray:NX_LTGRAY];
  [observeScrollView setDocView:observeMatrix];
  [observeBox addSubview:observeScrollView];
  [observeMatrix scrollCellToVisible:0 :0];
  [observeBox display];

  [observeSelPanel makeKeyAndOrderFront:self];

  [IGSCommand selectText:self];
  idle = 1;

  return self;
}

- cellClicked:theCell
{
  char str[80];
  int n;

  strcpy(str, [theCell stringValue]);
  sscanf(str, "%3d", &n);

  idle = 0;
  observegame(n);
  idle = 1;

  [observeSelPanel close];

  return self;
}

- IGSplayers:sender
{
  IGSSendString("players");
  IGSSendString("\n");

  return self;
}

- IGSquit:sender
{
  IGSSendString("quit");
  IGSSendString("\n");
  
  DPSRemoveTimedEntry(timer);

  gameType = LOCAL;
  [IGSPanel close];
  [IGSStatusPanel close];

  return self;
}

- IGSranks:sender
{
  IGSSendString("ranks");
  IGSSendString("\n");

  return self;
}

- IGSrefresh:sender
{
  [MainGoView refreshIO];

  return self;
}

- IGSreset:sender
{
  IGSSendString("reset");
  IGSSendString("\n");

  return self;
}

- IGSresign:sender
{
  IGSSendString("resign");
  IGSSendString("\n");

  return self;
}

- IGSsave:sender
{
  IGSSendString("save");
  IGSSendString("\n");

  return self;
}

- IGSstored:sender
{
  IGSSendString("stored");
  IGSSendString("\n");

  return self;
}

- IGSthist:sender
{
  IGSSendString("thist ");
  IGSSendString("\n");

  return self;
}

- IGSuptime:sender
{
  IGSSendString("uptime");
  IGSSendString("\n");

  return self;
}

- IGSwatching:sender
{
  IGSSendString("watching");
  IGSSendString("\n");

  return self;
}

- IGSwho:sender
{
  IGSSendString("who");
  IGSSendString("\n");

  return self;
}

@end
